﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Text;

namespace Pahan.McuFusion.Common.Utils
{
    public static class AssemblyLoader
    {
        /// <summary>
        /// Loads the assemblies from the specified directory.
        /// </summary>
        public static void LoadAll(String dir)
        {
            if (Directory.Exists(dir))
            {
                var files = Directory.GetFiles(dir, "*.dll");
                foreach (String file in files)
                {
                    try
                    {
                        var asm = Assembly.LoadFrom(Path.Combine(dir, file));
                        assemblies.Add(asm);
                    }
                    catch (Exception e)
                    {
                        // Do nothing.
                    }
                }
            }
        }

        /// <summary>
        /// Gets the list of all loaded assemblies.
        /// </summary>
        public static IList<Assembly> GetAssemblies()
        {
            return roAssemblies;
        }

        public static IList<T> GetObjects<T>() where T: class
        {
            var list = new List<T>();
            foreach (var assembly in GetAssemblies())
            {
                foreach (var type in assembly.GetTypes())
                {
                    if (!type.IsAbstract && !type.IsGenericTypeDefinition &&
                        !type.IsInterface && typeof(T).IsAssignableFrom(type))
                    {
                        try
                        {
                            var prog = Activator.CreateInstance(type);
                            list.Add((T)prog);
                        }
                        catch
                        {
                            // Do nothing.
                        }
                    }
                }
            }
            return list;
        }

        public static IList<Type> GetTypes<T>() where T : class
        {
            var list = new List<Type>();
            foreach (var assembly in GetAssemblies())
            {
                foreach (var type in assembly.GetTypes())
                {
                    if (!type.IsAbstract && !type.IsGenericTypeDefinition &&
                        !type.IsInterface && typeof(T).IsAssignableFrom(type))
                    {
                        try
                        {
                            list.Add(type);
                        }
                        catch
                        {
                            // Do nothing.
                        }
                    }
                }
            }
            return list;
        }

        public static IDisposable GetAssemblyResolutionScope()
        {
            return new AssemblyResolutionScope();
        }

        private static readonly List<Assembly> assemblies = new List<Assembly>()
        {
            Assembly.GetExecutingAssembly()
        };

        private static readonly ReadOnlyCollection<Assembly> roAssemblies =
            new ReadOnlyCollection<Assembly>(assemblies);
    }
}